package rahmath.sharif.docrypt.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;

import rahmath.sharif.docrypt.R;
import rahmath.sharif.docrypt.constant.DocryptConstants;
import rahmath.sharif.docrypt.entity.Data;
import rahmath.sharif.docrypt.entity.Vault;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.widget.EditText;

public class DocryptUtil implements DocryptConstants {

	public static double getSpaceAvailable() {
		StatFs stat = new StatFs(Environment.getExternalStorageDirectory()
				.getPath());
		return stat.getAvailableBlocks() * (double) stat.getBlockSize();
	}

	public static List<Vault> getVaultsFromSD() {
		File docryptVaultsDir = getDocryptDir(DOCRYPT_VAULTS);
		File[] vaultFiles = docryptVaultsDir.listFiles();
		ArrayList<Vault> vaults = new ArrayList<Vault>();
		for (File file : vaultFiles) {
			Vault vault = getVaultFromSD(file);
			if (null != vault) {
				vaults.add(vault);
			}
		}
		return vaults;
	}

	private static Vault getVaultFromSD(File file) {
		try {
			FileInputStream fileInputStream = new FileInputStream(file);
			ObjectInputStream objectInputStream = new ObjectInputStream(
					fileInputStream);
			Vault vault = (Vault) objectInputStream.readObject();
			objectInputStream.close();
			return vault;
		} catch (StreamCorruptedException e) {
		} catch (OptionalDataException e) {
		} catch (IOException e) {
		} catch (ClassNotFoundException e) {
		}
		return null;
	}

	public static Vault getVaultFromSD(String vaultFileName) {
		File vaultFile = new File(getDocryptDir(DOCRYPT_VAULTS)
				+ DocryptConstants.FILE_SEPARATOR + vaultFileName);
		return getVaultFromSD(vaultFile);
	}

	public static String getTextFromFile(String textFileName) {
		BufferedReader bufferedReader = null;
		File textFile = new File(getDocryptDir(DOCRYPT_DATAS_TEXTS),
				textFileName);
		if (!textFile.exists()) {
			return "";
		}
		try {
			FileReader fileReader = new FileReader(textFile);
			bufferedReader = new BufferedReader(fileReader);
			StringBuilder stringBuilder = new StringBuilder();
			String line = null;
			while (null != (line = bufferedReader.readLine())) {
				stringBuilder.append(line);
			}
			return stringBuilder.toString();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bufferedReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return "";
	}

	public static String getCleanTextFromFile(String seed, String textFileName) {
		return AESCryptor.decrypt(256, seed, getTextFromFile(textFileName));
	}

	public static boolean putVaultToSD(Vault vault) {
		if (null == vault) {
			return false;
		}
		File vaultFile = new File(getDocryptDir(DOCRYPT_VAULTS),
				vault.getVaultFileName());
		try {
			FileOutputStream fos = new FileOutputStream(vaultFile);
			ObjectOutputStream os = new ObjectOutputStream(fos);
			os.writeObject(vault);
			os.close();
			return true;
		} catch (FileNotFoundException e) {
		} catch (IOException e) {
		}
		return false;
	}

	public static boolean putCipherTextToFile(String cipherText,
			String textFileName) {
		try {
			File textFile = new File(getDocryptDir(DOCRYPT_DATAS_TEXTS),
					textFileName);
			FileWriter fileWriter = new FileWriter(textFile);
			fileWriter.write(cipherText);
			fileWriter.close();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	public static File getDocryptDir(int type) {
		boolean mExternalStorageAvailable = false;
		boolean mExternalStorageWriteable = false;
		String state = Environment.getExternalStorageState();
		if (Environment.MEDIA_MOUNTED.equals(state)) {
			// We can read and write the media
			mExternalStorageAvailable = mExternalStorageWriteable = true;
		} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
			// We can only read the media
			mExternalStorageAvailable = true;
			mExternalStorageWriteable = false;
		} else {
			// Something else is wrong. It may be one of many other states, but
			// all we need to know is we can neither read nor write
			mExternalStorageAvailable = mExternalStorageWriteable = false;
		}
		if (mExternalStorageAvailable && mExternalStorageWriteable) {
			File externalStorage = Environment.getExternalStorageDirectory();
			File folder = null;
			switch (type) {
			case DOCRYPT:
				folder = new File(externalStorage.getAbsolutePath()
						+ "/Docrypt");
				break;
			case DOCRYPT_EXTRACTED:
				folder = new File(externalStorage.getAbsolutePath()
						+ "/Docrypt/Extracted");
				break;
			case DOCRYPT_DATAS:
				folder = new File(externalStorage.getAbsolutePath()
						+ "/Docrypt/Datas");
				break;
			case DOCRYPT_VAULTS:
				folder = new File(externalStorage.getAbsolutePath()
						+ "/Docrypt/Vaults");
				break;
			case DOCRYPT_DATAS_TEXTS:
				folder = new File(externalStorage.getAbsolutePath()
						+ "/Docrypt/Datas/Texts");
				break;
			case DOCRYPT_DATAS_ATTACHMENTS:
				folder = new File(externalStorage.getAbsolutePath()
						+ "/Docrypt/Datas/Attachments");
				break;
			case DOCRYPT_DRIVE_FOLDER:
				folder = new File(externalStorage.getAbsolutePath()
						+ "/Docrypt/Drive");
				break;
			default:
				break;
			}
			if (!folder.exists()) {
				folder.mkdirs();
			}
			return folder;
		} else {
			throw new UnsupportedOperationException("SD Card is not available");
		}
	}

	public static boolean deleteVaultFromSD(Vault vault) {
		File vaultFile = new File(getDocryptDir(DOCRYPT_VAULTS),
				vault.getVaultFileName());
		boolean success = vaultFile.delete();
		// Clean up related stuffs
		Collection<Data> collection = vault.getDatas().values();
		File textsDir = getDocryptDir(DOCRYPT_DATAS_TEXTS);
		File attachmentsDir = getDocryptDir(DOCRYPT_DATAS_ATTACHMENTS);
		for (Data data : collection) {
			new File(textsDir, data.getTextFileName()).delete();
			Collection<String> attachmentFileNames = data.getAttachments()
					.values();
			for (String attachmentFileName : attachmentFileNames) {
				new File(attachmentsDir, attachmentFileName).delete();
			}
		}
		return success;
	}

	public static boolean deleteDataFromSD(Vault vault, String dataKey) {
		File textsDir = getDocryptDir(DOCRYPT_DATAS_TEXTS);
		File attachmentsDir = getDocryptDir(DOCRYPT_DATAS_ATTACHMENTS);
		Data data = vault.getDatas().get(dataKey);
		boolean success = new File(textsDir, data.getTextFileName()).delete();
		// Clean up related stuffs
		Collection<String> attachmentFileNames = data.getAttachments().values();
		for (String attachmentFileName : attachmentFileNames) {
			new File(attachmentsDir, attachmentFileName).delete();
		}
		return success;
	}

	@TargetApi(11)
	@SuppressWarnings("deprecation")
	public static void doPaste(Activity activity, int editTextId) {
		android.text.ClipboardManager textClipboardManager = (android.text.ClipboardManager) activity
				.getSystemService(Context.CLIPBOARD_SERVICE);
		String clipString;
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
			ClipboardManager contentClipboardManager = (ClipboardManager) activity
					.getSystemService(Context.CLIPBOARD_SERVICE);
			try {
				clipString = contentClipboardManager.getPrimaryClip()
						.getItemAt(0).coerceToText(activity).toString();
			} catch (Exception e) {
				clipString = "";
			}
		} else {
			if (textClipboardManager.hasText()) {
				clipString = textClipboardManager.getText().toString();
			} else {
				clipString = "";
			}
		}
		((EditText) activity.findViewById(editTextId)).setText(clipString);
	}

	@TargetApi(11)
	@SuppressWarnings("deprecation")
	public static void doCopy(Activity activity, int editTextId) {
		android.text.ClipboardManager textClipboardManager = (android.text.ClipboardManager) activity
				.getSystemService(Context.CLIPBOARD_SERVICE);
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
			ClipboardManager contentClipboardManager = (ClipboardManager) activity
					.getSystemService(Context.CLIPBOARD_SERVICE);
			contentClipboardManager.setPrimaryClip(ClipData.newPlainText(
					"Output Text", ((EditText) activity
							.findViewById(R.id.editTextOutputText)).getText()
							.toString()));
		} else {
			textClipboardManager.setText(((EditText) activity
					.findViewById(R.id.editTextOutputText)).getText()
					.toString());
		}
	}

	public static boolean deleteFiles(File[] selectedFiles,
			Properties fileNameMap, Properties mimeMap) {
		boolean complete = true;
		for (File file : selectedFiles) {
			if (file.isDirectory()) {
				deleteFiles(file.listFiles(), fileNameMap, mimeMap);
				if (!file.delete()) {
					complete = false;
				} else {
					fileNameMap.remove(file.getAbsolutePath());
					mimeMap.remove(file.getAbsolutePath());
				}
			} else {
				if (!file.delete()) {
					complete = false;
				} else {
					fileNameMap.remove(file.getAbsolutePath());
					mimeMap.remove(file.getAbsolutePath());
				}
			}
		}
		return complete;
	}

}
